/**
 * Generali Solutions d'assurances - Tous droits réservés &copy; 2007 - 2010
 */

package fr.generali.accueilclient.client.assembler.output;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import fr.generali.accueilclient.client.om.IAdresse;
import fr.generali.accueilclient.client.om.IClientAssociation;
import fr.generali.accueilclient.client.om.IClientAutre;
import fr.generali.accueilclient.client.om.IClientCollectivite;
import fr.generali.accueilclient.client.om.IClientCopropriete;
import fr.generali.accueilclient.client.om.IClientEntreprise;
import fr.generali.accueilclient.client.om.IClientParticulier;
import fr.generali.accueilclient.client.om.IClientProfessionnel;
import fr.generali.accueilclient.client.om.ICoordonneeBancaire;
import fr.generali.accueilclient.client.om.IEmail;
import fr.generali.accueilclient.client.om.IPersonne;
import fr.generali.accueilclient.client.om.IPersonneMorale;
import fr.generali.accueilclient.client.om.IPersonnePhysique;
import fr.generali.accueilclient.client.om.ISiteInternet;
import fr.generali.accueilclient.client.om.ITelephone;
import fr.generali.accueilclient.client.om.NaturePersonne;
import fr.generali.accueilclient.client.om.impl.Communication;
import fr.generali.refservcommuns.rce.consultpersonnecontact.dossierpersonnecontact.DtoDossierP42;
import fr.generali.refservcommuns.rce.servperscom.ctc.gestioncontacts.DtoDossierContact;
import fr.generali.refservcommuns.rce.servperscom.ctc.gestioncontacts.DtoInformationCommunication;
import fr.generali.refservcommuns.rce.servperscom.pty.personnes.DtoPersonneMorale;
import fr.generali.refservcommuns.rce.servperscom.pty.personnes.DtoPersonnePhysique;
import fr.generali.refservcommuns.rce.servperscom.pty.profilmarketingpersonnes.DtoProfilMarketing;
import fr.generali.refservcommuns.rce.servperscom.pty.referencebancaire.DtoDossierCoordonneesBancaires;

/**
 * Transforme un {@link DtoDossierP42} en {@link IPersonne}
 * 
 * @author selrhazala
 */
@Component("dtoDossierP42ToPersonneConverter")
public class DtoDossierP42ToPersonneConverter implements Converter<DtoDossierP42, IPersonne> {

    /**
     * LOGGER
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(DtoDossierP42ToPersonneConverter.class);

    /**
     * Assembler de personne physique
     */
    @Autowired
    @Qualifier("dtoPersonnePhysique2PersonnePhysiqueConverter")
    private Converter<DtoPersonnePhysique, IPersonnePhysique> dtoPersonnePhysique2PersonnePhysiqueConverter;

    /**
     * Assembler de personne morale
     */
    @Autowired
    @Qualifier("dtoPersonneMorale2PersonneMoraleConverter")
    private Converter<DtoPersonneMorale, IPersonneMorale> dtoPersonneMorale2PersonneMoraleConverter;

    /**
     * Assembler pour un particulier
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientParticulierConverter")
    private Converter<DtoDossierP42, IClientParticulier> dtoDossierP42ToClientParticulierConverter;

    /**
     * Assembler pour un pro
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientProfessionnelConverter")
    private Converter<DtoDossierP42, IClientProfessionnel> dtoDossierP42ToClientProfessionnelConverter;

    /**
     * Assembler pour une association
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientAssociationConverter")
    private Converter<DtoDossierP42, IClientAssociation> dtoDossierP42ToClientAssociationConverter;

    /**
     * Assembler pour une collectivité
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientCollectiviteConverter")
    private Converter<DtoDossierP42, IClientCollectivite> dtoDossierP42ToClientCollectiviteConverter;

    /**
     * Assembler pour une copropriété
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientCoproprieteConverter")
    private Converter<DtoDossierP42, IClientCopropriete> dtoDossierP42ToClientCoproprieteConverter;

    /**
     * Assembler pour une entreprise
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientEntrepriseConverter")
    private Converter<DtoDossierP42, IClientEntreprise> dtoDossierP42ToClientEntrepriseConverter;

    /**
     * Assembler pour tout autre type de client
     */
    @Autowired
    @Qualifier("dtoDossierP42ToClientAutreConverter")
    private Converter<DtoDossierP42, IClientAutre> dtoDossierP42ToClientAutreConverter;

    /**
     * Permet de mapper adresse, téléphone et email
     */
    @Autowired
    private DonneesContactMapper donneesContactMapper;

    /**
     * Permet de mapper le rib
     */
    @Autowired
    @Qualifier("dtoDossierCoordonneesBancaires2ListCoordonneeBancaireConverter")
    private Converter<List<DtoDossierCoordonneesBancaires>, List<ICoordonneeBancaire>> dtoDossierCoordonneesBancaires2ListCoordonneeBancaireConverter;

    /**
     * {@inheritDoc}
     */
    public IPersonne convert(DtoDossierP42 input) {
        LOGGER.debug("assemble");

        DtoPersonneMorale personneMorale = input.getPersonneMorale();
        DtoPersonnePhysique personnePhysique = input.getPersonnePhysique();
        boolean isPersonnePhysique = personneMorale == null && personnePhysique != null;
        boolean isPersonneMorale = personneMorale != null;
        NaturePersonne nature = calculerNature(personneMorale, personnePhysique, isPersonnePhysique, isPersonneMorale);

        IPersonne client = buildClient(input, nature);

        if (NaturePersonne.PARTICULIER.equals(nature) || NaturePersonne.PROFESSIONNEL.equals(nature)) {
            mapperPersonnePhysique(personnePhysique, client, input.getDossierCoordonneesBancaires(),
                                input.getDossierContact(), input.getProfilMarketing());
        } else {
            mapperPersonneMorale(personneMorale, client, input.getDossierCoordonneesBancaires(),
                                input.getDossierContact(), input.getProfilMarketing());
        }

        return client;
    }
    
    /**
     * Détermine la nature de la personne
     * 
     * @param personneMorale la personne morale
     * @param personnePhysique la personne physique
     * @param isPersonnePhysique true si c'est une personne physique
     * @param isPersonneMorale true si c'est une personne morale
     * @return la nature de la personne
     */
    private NaturePersonne calculerNature(DtoPersonneMorale personneMorale, DtoPersonnePhysique personnePhysique,
                    boolean isPersonnePhysique, boolean isPersonneMorale) {
        NaturePersonne nature = NaturePersonne.PARTICULIER;
        if (isPersonnePhysique && personnePhysique.getParticulierProfessionnel() != null
                        && !personnePhysique.getParticulierProfessionnel().isEmpty()) {
            nature = NaturePersonne.PROFESSIONNEL;
        } else {
            if (isPersonneMorale) {
                nature = NaturePersonne.getNaturePersonneFromValue(personneMorale.getTypePersonneMorale());
            }
        }
        return nature;
    }

    /**
     * @param input un {@link DtoDossierP42}
     * @param nature la nature personne
     * @return une personne
     */
    private IPersonne buildClient(DtoDossierP42 input, NaturePersonne nature) {
        IPersonne client;
        switch (nature) {
            case PARTICULIER:
                client = dtoDossierP42ToClientParticulierConverter.convert(input);
                break;
            case PROFESSIONNEL:
                client = dtoDossierP42ToClientProfessionnelConverter.convert(input);
                break;
            case ASSOCIATION:
                client = dtoDossierP42ToClientAssociationConverter.convert(input);
                break;
            case COLLECTIVITE:
                client = dtoDossierP42ToClientCollectiviteConverter.convert(input);
                break;
            case COPROPRIETE:
                client = dtoDossierP42ToClientCoproprieteConverter.convert(input);
                break;
            case ENTREPRISE:
                client = dtoDossierP42ToClientEntrepriseConverter.convert(input);
                break;
            default:
                client = dtoDossierP42ToClientAutreConverter.convert(input);
                break;
        }
        return client;
    }

    /**
     * Mappe une personne physique
     * 
     * @param personnePhysique la personne physique
     * @param client la personne
     * @param listeDossierCoordonneesBancaires la liste des Coordonnees Bancaires
     * @param dossierContact le dossier contact
     * @param profilMarketing le profile marketing de la personne
     */
    private void mapperPersonnePhysique(DtoPersonnePhysique personnePhysique, IPersonne client, 
                    List<DtoDossierCoordonneesBancaires> listeDossierCoordonneesBancaires,
                    DtoDossierContact dossierContact, DtoProfilMarketing profilMarketing) {
        // Récupération des informations du niveau IPersonnePhysique
        IPersonnePhysique.class.cast(client).setPersonnePhysique(
                        dtoPersonnePhysique2PersonnePhysiqueConverter.convert(personnePhysique));
        // Récupération des informations du niveau IPersonne
        client.setNumeroClient(personnePhysique.getIdentifiantPersonne());
        if (StringUtils.isNotEmpty(personnePhysique.getVisibilite().getIdentifiantClientAgent())) {
            client.setNumeroClientAgent(personnePhysique.getVisibilite().getIdentifiantClientAgent());
        }
        client.setCodeIntermediaire(personnePhysique.getVisibilite().getIdentifiantIntermediaire());
        client.setTypeClient(personnePhysique.getStatutClient());
        if (personnePhysique.getDateDebutClient() != null) {
            client.setDateDebut(personnePhysique.getDateDebutClient().toGregorianCalendar().getTime());
            client.setDatePassageClient(personnePhysique.getDateDebutClient().toGregorianCalendar().getTime());
        }
        
        if (personnePhysique.getDateFinClient() != null) {
            client.setDateFinClient(personnePhysique.getDateFinClient().toGregorianCalendar().getTime());
        }
        
        buildCoordonneesBancaires(client, listeDossierCoordonneesBancaires);
        buildCoordonneesContact(client, dossierContact, profilMarketing);
    }

    /**
     * Mappe une personne morale
     * 
     * @param personneMorale la personne morale
     * @param client la personne
     * @param listeDossierCoordonneesBancaires la liste des Coordonnees Bancaires
     * @param dossierContact le dossier contact
     * @param profilMarketing le profile marketing de la personne
     */
    private void mapperPersonneMorale(DtoPersonneMorale personneMorale, IPersonne client,
                    List<DtoDossierCoordonneesBancaires> listeDossierCoordonneesBancaires,
                    DtoDossierContact dossierContact, DtoProfilMarketing profilMarketing) {
        // Récupération des informations du niveau IPersonneMorale
        IPersonneMorale.class.cast(client).setPersonneMorale(
                        dtoPersonneMorale2PersonneMoraleConverter.convert(personneMorale));
        // Récupération des informations du niveau IPersonne
        client.setNumeroClient(personneMorale.getIdentifiantPersonne());
        if (StringUtils.isNotEmpty(personneMorale.getVisibilite().getIdentifiantClientAgent())) {
            client.setNumeroClientAgent(personneMorale.getVisibilite().getIdentifiantClientAgent());
        }
        client.setCodeIntermediaire(personneMorale.getVisibilite().getIdentifiantIntermediaire());
        client.setTypeClient(personneMorale.getStatutClient());
        if (personneMorale.getDateDebutClient() != null) {
            client.setDateDebut(personneMorale.getDateDebutClient().toGregorianCalendar().getTime());
            client.setDatePassageClient(personneMorale.getDateDebutClient().toGregorianCalendar().getTime());
        }
        
        if (personneMorale.getDateFinClient() != null) {
            client.setDateFinClient(personneMorale.getDateFinClient().toGregorianCalendar().getTime());
        }

        buildCoordonneesBancaires(client, listeDossierCoordonneesBancaires);
        buildCoordonneesContact(client, dossierContact, profilMarketing);
    }

    /**
     * Construit les coordonnées bancaires du client
     * 
     * @param client le client
     * @param listeDossierCoordonneesBancaires ses coordonnées bancaires
     */
    private void buildCoordonneesBancaires(IPersonne client,
                    List<DtoDossierCoordonneesBancaires> listeDossierCoordonneesBancaires) {
        client.setListeCoordonneesBancaires(dtoDossierCoordonneesBancaires2ListCoordonneeBancaireConverter
                        .convert(listeDossierCoordonneesBancaires));
        if (client.getListeCoordonneesBancaires() != null && !client.getListeCoordonneesBancaires().isEmpty()) {
            client.setCoordonneeBancaire(client.getListeCoordonneesBancaires().get(0));
        }
    }

    /**
     * Construit les coordonnées de contact du client
     * 
     * @param client le client
     * @param dossierContact ses coordonnées
     * @param profilMarketing le profile marketing de la personne
     */
    private void buildCoordonneesContact(IPersonne client, DtoDossierContact dossierContact,
                    DtoProfilMarketing profilMarketing) {
        if (dossierContact != null) {
            buildAdresses(client, dossierContact, profilMarketing);
            buildTelephones(client, dossierContact);
            buildEmails(client, dossierContact);
            buildSiteInternets(client, dossierContact);
            buildCommunicationClient(client, dossierContact);
        }
    }
    
    /**
     * Construit les coordonnées de type adresse du client
     * 
     * @param client le client
     * @param dossierContact ses coordonnées
     * @param profilMarketing le profile marketing de la personne
     */
    private void buildAdresses(IPersonne client, DtoDossierContact dossierContact, DtoProfilMarketing profilMarketing) {
        if (dossierContact != null) {            
            client.setAdressePrincipale(donneesContactMapper
                            .getAdressePrincipale(dossierContact.getAdressePrincipale(), profilMarketing));

            List<IAdresse> listeAdresses = new ArrayList<IAdresse>();
            listeAdresses =
                            donneesContactMapper.getListeAdressePrincipale(dossierContact.getAdressePrincipale(),
                                            listeAdresses, profilMarketing);
            listeAdresses =
                            donneesContactMapper.getListeAdresseCourrier(dossierContact.getAdresseCourrier(),
                                            listeAdresses, profilMarketing);
            listeAdresses =
                            donneesContactMapper.getListeAdresseFiscale(dossierContact.getAdresseFiscale(),
                                            listeAdresses, profilMarketing);
            listeAdresses =
                            donneesContactMapper.getListeAdresseSecondaire(dossierContact.getAdresseSecondaire(),
                                            listeAdresses, profilMarketing);
            client.setListeAdresse(listeAdresses);
        }
    }
    
    /**
     * Construit les coordonnées de type telephone du client
     * 
     * @param client le client
     * @param dossierContact ses coordonnées
     */
    private void buildTelephones(IPersonne client, DtoDossierContact dossierContact) {
        if (dossierContact != null) {            
            List<ITelephone> listeTelephones = new ArrayList<ITelephone>();
            listeTelephones =
                            donneesContactMapper.getListeTelephone(dossierContact.getTelephonePrincipal(),
                                            listeTelephones, true);
            listeTelephones =
                            donneesContactMapper.getListeTelephone(dossierContact.getTelephoneSecondaire(),
                                            listeTelephones, false);
            client.setListeTelephone(listeTelephones);
        }
    }
    
    /**
     * Construit les coordonnées de type email du client
     * 
     * @param client le client
     * @param dossierContact ses coordonnées
     */
    private void buildEmails(IPersonne client, DtoDossierContact dossierContact) {
        if (dossierContact != null) {      
            client.setEmail(donneesContactMapper.getEmail(dossierContact.getCourrielPrincipal()));
            
            List<IEmail> listeEmails = new ArrayList<IEmail>();
            listeEmails = donneesContactMapper.getListeEmail(dossierContact.getCourrielPrincipal(), listeEmails, true);
            listeEmails =
                            donneesContactMapper.getListeEmail(dossierContact.getCourrielSecondaire(), listeEmails,
                                            false);
            client.setListeEmail(listeEmails);

            if (client.getEmail() == null && CollectionUtils.isNotEmpty(listeEmails)) {
                client.setEmail(listeEmails.get(0));
            }
        }
    }
    
    /**
     * Construit les coordonnées de type site internet du client
     * 
     * @param client le client
     * @param dossierContact ses coordonnées
     */
    private void buildSiteInternets(IPersonne client, DtoDossierContact dossierContact) {
        if (dossierContact != null) {            
            List<ISiteInternet> listeSiteInternets = new ArrayList<ISiteInternet>();
            listeSiteInternets =
                            donneesContactMapper.getListeSiteInternet(dossierContact.getPageWebPrincipale(),
                                            listeSiteInternets, true);
            listeSiteInternets =
                            donneesContactMapper.getListeSiteInternet(dossierContact.getPageWebSecondaire(),
                                            listeSiteInternets, false);
            client.setListeSiteInternet(listeSiteInternets);
        }
    }
    
    /**
     * Construit les coordonnées de type communication du client
     * 
     * @param client le client
     * @param dossierContact ses coordonnées
     */
    private void buildCommunicationClient(IPersonne client, DtoDossierContact dossierContact) {
        if (dossierContact != null) {            
            if (CollectionUtils.isNotEmpty(dossierContact.getStopCom())) {

                // Chargement des stopComs
                DtoInformationCommunication dtoInformationCommunication = dossierContact.getStopCom().get(0);
                Communication communication = new Communication();
                communication.setCanalDePreference(dossierContact.getCodeCanalPrefere());
                communication.setAutorisation((dossierContact.getDemarchage() != null 
                                && dossierContact.getDemarchage().isIndicateurAutorisationInformation() != null)
                                ? dossierContact.getDemarchage().isIndicateurAutorisationInformation()
                                : false);
                if (dtoInformationCommunication != null) {
                    communication.setEmailOk(dtoInformationCommunication.isIndicateurStopCourriel() == null ? true
                                    : !dtoInformationCommunication.isIndicateurStopCourriel());
                    communication.setCourrierOk(dtoInformationCommunication.isIndicateurStopCourrier() == null ? true
                                    : !dtoInformationCommunication.isIndicateurStopCourrier());
                    communication.setSmsOk(dtoInformationCommunication.isIndicateurStopSMS() == null ? true
                                    : !dtoInformationCommunication.isIndicateurStopSMS());
                    communication.setTelephoneOk(
                                    dtoInformationCommunication.isIndicateurStopTelephone() == null ? true
                                                    : !dtoInformationCommunication.isIndicateurStopTelephone());
                } else {
                    communication.setEmailOk(true);
                    communication.setCourrierOk(true);
                    communication.setSmsOk(true);
                    communication.setTelephoneOk(true);
                }
                client.setCommunication(communication);
            } else {
                // Initialisation des stopComs
                Communication communication = new Communication();
                communication.setEmailOk(true);
                communication.setCourrierOk(true);
                communication.setAutorisation(false);
                communication.setSmsOk(true);
                communication.setTelephoneOk(true);

                client.setCommunication(communication);
            }
        }
    }
}
